package com.ybg.block.core.eth.remoteapi;

import com.alibaba.fastjson.JSONObject;
import com.ybg.block.core.dbapi.entity.BlockWallet;
import com.ybg.block.core.dbapi.service.BlockWalletService;
import com.ybg.block.core.eth.config.EthHttpServiceProperties;
import com.ybg.framework.vo.R;
import com.ybg.share.core.enums.WalletType;
import com.ybg.share.core.eth.EthWalletRemoteApi;
import com.ybg.share.core.eth.vo.EthWallet;
import com.ybg.share.core.eth.vo.EthWalletSendResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.web3j.crypto.*;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tx.Transfer;
import org.web3j.utils.Convert;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;

@Slf4j
@Service(version = "${dubbo.provider.version}", timeout = 120000, cache = "false")
public class EthWalletRemoteApiImpl implements EthWalletRemoteApi {

    @Autowired
    private BlockWalletService blockWalletService;
    @Autowired
    private EthHttpServiceProperties ethHttpServiceProperties;
    @Autowired
    private Web3j web3j;

    @Override
    public R<String> addWallet(String password) {
        try {
            if (ethHttpServiceProperties.getUseFullScrypt() == null) {
                throw new RuntimeException("没有配置加密方式");
            }
            WalletFile walletFile;
            ECKeyPair ecKeyPair = Keys.createEcKeyPair();
            if (ethHttpServiceProperties.getUseFullScrypt()) {
                walletFile = Wallet.createStandard(password, ecKeyPair);
            } else {
                walletFile = Wallet.createLight(password, ecKeyPair);
            }
            BlockWallet entity = new BlockWallet();
            entity.setWalletType(WalletType.ETH.getValue());
            entity.setCreateTime(LocalDateTime.now());

            entity.setPassword(password);
            entity.setFileData(JSONObject.toJSONString(walletFile));
            blockWalletService.save(entity);
            return R.success(walletFile.getAddress());
        } catch (Exception e) {
            log.error("{}", e);
            e.printStackTrace();
            return R.fail("生成失败");
        }

    }

    @Override
    public R<EthWallet> loadWallet(String password, String address) {
        BlockWallet blockWallet = blockWalletService.getByAddress(address);
        if (blockWallet == null) {
            return R.fail("钱包为不存在");
        }
        try {
            String passWord = password;
            Credentials credentials = WalletUtils.loadJsonCredentials(passWord, blockWallet.getFileData());
            BigInteger publicKey = credentials.getEcKeyPair().getPublicKey();
            BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey();
            if (log.isDebugEnabled()) {
                log.info("address=" + address);
                log.info("public key=" + publicKey);
                log.info("private key=" + privateKey);
            }
            EthWallet ethWallet = new EthWallet();
            ethWallet.setAddress(address);
            ethWallet.setPublicKey(publicKey.toString());
            ethWallet.setPrivateKey(privateKey.toString());
            return R.success(ethWallet);
        } catch (Exception e) {
            log.error("{}", e);
            return R.fail("发生异常");
        }
    }


    @Override
    public R<EthWalletSendResult> tradeTo(String sendAddress, String password, String receiveAddress, BigDecimal value) {
        BlockWallet blockWallet = blockWalletService.getByAddress(sendAddress);
        if (blockWallet == null) {
            return R.fail("钱包为不存在");
        }
        EthWalletSendResult result;
        try {
            Credentials credentials = WalletUtils.loadJsonCredentials(password, blockWallet.getFileData());

            TransactionReceipt send = Transfer.sendFunds(web3j, credentials, receiveAddress, value, Convert.Unit.ETHER).send();
            if (log.isDebugEnabled()) {
                log.info("Transaction complete:");
                log.info("trans hash=" + send.getTransactionHash());
                log.info("from :" + send.getFrom());
                log.info("to:" + send.getTo());
                log.info("gas used=" + send.getGasUsed());
                log.info("status: " + send.getStatus());
            }
            result = new EthWalletSendResult();
            BeanUtils.copyProperties(send, result);
        } catch (Exception e) {
            log.error("{}", e);
            return R.fail("发送失败");
        }
        return R.success(result);
    }

    @Override
    public R<String> getAddressBalance(String address) {
        try {
            //HEX String - 一个整数块号
            //String "earliest" 为最早/起源块
            //String "latest" - 为最新的采矿块
            //String "pending" - 待处理状态/交易
            //第二个参数：区块的参数，建议选最新区块
            EthGetBalance balance = web3j.ethGetBalance(address, DefaultBlockParameter.valueOf("latest")).send();
            if (balance.getResult() == null) {
                return R.success("0");
            }
            //格式转化 wei-ether
            //以太坊中，如果没有特殊标示，数字的单位都是小数点后18位，因此查询账户余额有必要将wei转化成ether。
            String balanceETH = Convert.fromWei(balance.getBalance().toString(), Convert.Unit.ETHER).toPlainString().concat(" ether");
            return R.success(balanceETH);
        } catch (Exception e) {
            log.error("{}", e);
            return R.fail("查询失败");
        }


    }


}
